/*
Modify the program in Listing 7-1 ( free_and_sbrk.c ) to print out the current value of
the program break after each execution of malloc(). Run the program specifying a
small allocation block size. This will demonstrate that malloc() doesn’t employ sbrk()
to adjust the program break on each call, but instead periodically allocates larger
chunks of memory from which it passes back small pieces to the caller.
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define MAX_ALLOCS 1000000

/*
You have to run more allocations:
./a.out 1000 10240 2
 */
// TODO. char as pointer container?
int
main(int argc, char *argv[])
{
  char *ptr[MAX_ALLOCS];
  int freeStep, freeMin, freeMax, blockSize, numAllocs, j;
  printf("\n");
  if (argc < 3 || strcmp(argv[1], "--help") == 0)
    return EXIT_FAILURE;

  numAllocs = atoi(argv[1]);
  if (numAllocs > MAX_ALLOCS)
    return EXIT_FAILURE;

  blockSize = atoi(argv[2]);
  freeStep = argc > 3 ? atoi(argv[3]) : 1;
  freeMin = argc > 4 ? atoi(argv[4]) : 1;
  freeMax = argc > 5 ? atoi(argv[5]) : numAllocs;

  if (freeMax > numAllocs)
    return EXIT_FAILURE;

  printf("Initial program break: %10p\n", sbrk(0));
  printf("Allocating %d*%d bytes\n", numAllocs, blockSize);
  for (j = 0; j < numAllocs; ++j)
    {
      ptr[j] = malloc(blockSize);
      printf("Program break after malloc: %p\n", sbrk(0));
      if (ptr[j] == NULL)
        return EXIT_FAILURE;
    }
  printf("Program break is now: %p\n", sbrk(0));
  printf("Freeing blocks from %d to %d in steps of %d\n",
         freeMin, freeMax, freeStep);
  for (j = freeMin - 1; j < freeMax; j += freeStep)
    free(ptr[j]);

  printf("After free(), program break is: %p\n", sbrk(0));
  return EXIT_SUCCESS;
}
